package com.aceitunaproject.server.terrain;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.aceitunaproject.server.ServerConfiguration;
import com.aceitunaproject.server.entity.unit.Unit;
import com.aceitunaproject.server.equipment.Equipment;
import com.aceitunaproject.server.map.MapTile;

/**
 * Static class to manage the TerrainType classes, needed because they are not
 * managed objects.
 * 
 * If the terrain types are saved as managed objects in the dstar object store,
 * each time they are consulted an extra layer would be involved. 
 * Since there is no need to save them there (as they are not changed by the game, they are
 * taken from configuration files or similar sources), only the ids of the
 * terrain types will be saved in the Managed Objects.
 * The terrain manager will be called by them to obtain the full TerrainType class instance.
 * 
 * @author Federico Bergstein
 * 
 */
public class TerrainManager {

	//All the possible terrain types
	private static Map<String, TerrainType> allTerrainTypes;
	
	//A class responsible for obtaining the terrain types from the source (configuration file, web service, etc) 
	private static TerrainTypeLoader terrainTypeLoader;

	/**
	 * Gets a terrain type loader from the ServerConfiguration if it is null.
	 * 
	 * @return a Terrain Type Loader
	 */
	private static TerrainTypeLoader getTerrainTypeLoader() {
		if (terrainTypeLoader == null) {
			terrainTypeLoader = ServerConfiguration.getTerrainTypeLoader();

		}
		return terrainTypeLoader;
	}

	/**
	 * Sets a Terrain Type Loader class, bypassing ServerConfiguration, usefull for tests.
	 * @param terrainTypeLoader the Terrain Type Loader
	 */
	public static void setTerrainTypeLoader(TerrainTypeLoader terrainTypeLoader) {
		TerrainManager.terrainTypeLoader = terrainTypeLoader;
	}

	/**
	 * 
	 * Returns all terrain Types.
	 * 
	 * @return All the possible Terrain Types
	 * 	 
	 * */
	public static Map<String, TerrainType> getAllTerrainTypes() {
		if (allTerrainTypes == null && getTerrainTypeLoader() != null) {

			allTerrainTypes = getTerrainTypeLoader().getTerrainTypes();
		}

		return allTerrainTypes;
	}

	
	/**
	 * From a given list of terrain type ids, returns a map with the actual objects.
	 * @param terrainTypeIDs A list of the ids of the TerrainType instances to retrieve
	 * @return A map with the TerrainType Instances with the received IDs
	 */
	public static Map<String, TerrainType> getTerrainTypeCollection(
			List<String> terrainTypeIDs) {

		Map<String, TerrainType> map = new HashMap<String, TerrainType>();
		for (String id : terrainTypeIDs) {
			map.put(id, getAllTerrainTypes().get(id));
		}

		return map;
	}

	/**
	 * Calculates the movement cost for an unit entering a tile, according to the unit's equipment and the map tile terrain types.
	 * @param unit the unit that would move into the tile
	 * @param tile the tile to be occupied by the unit
	 * @return the cost in Time Units.
	 */
	public static int calculateMovementCost(Unit unit, MapTile tile) {

		int cost = ServerConfiguration.getBasicMovementCost();

		for (TerrainType terrain : tile.getTerrainTypes().values()) {
			for (Equipment equipment : unit.getEquipment().values()) {
				cost += terrain.getMovementEffects(equipment).getTimeUnitCost();
			}
		}

		return cost;

	}
	
	//resets the class 
	public static void reset()
	{
		allTerrainTypes = null;
		terrainTypeLoader = null;
	
	}
	

}
